package com.gpj.learn.springcloud.ribbon.alone;

import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.LoadBalancerBuilder;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import rx.Observable;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className LoadBalancer
 * @description
 *   TODO
 * @author GPJ
 * @date 2021/9/26 16:09
 * @version 1.0
 **/
@Slf4j
@Service
public class LoadBalancer {
	@Autowired
	private DiscoveryClient discoveryClient;

	private Map<String, ILoadBalancer> loadBalancers = new HashMap<>();

	public String request(String serviceName, String url, String method){
		if(!loadBalancers.containsKey(serviceName)){
			// 获取服务列表
			List<ServiceInstance> servers = discoveryClient.getInstances(serviceName);
			List<Server> list = servers.stream()
					.map(server -> new Server(server.getHost(), server.getPort()))
					.collect(Collectors.toList());

			// 构建负载实例
			BaseLoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder()
					.buildFixedServerListLoadBalancer(list);
			loadBalancers.put(serviceName, loadBalancer);
		}

		return LoadBalancerCommand.<String>builder()
				.withLoadBalancer(loadBalancers.get(serviceName)).build()
				.submit(server -> call(server, url, method))
				.toBlocking().first();
	}
	
	private Observable<String> call(Server server, String url, String method){
		String addr = "http://" + server.getHost() + ":" + server.getPort() + url;
		log.info("调用地址:{}", addr);

		try {
			HttpURLConnection conn = (HttpURLConnection) new URL(addr).openConnection();
			conn.setRequestMethod(method);
			conn.connect();
			InputStream in = conn.getInputStream();
			byte[] data = new byte[in.available()];
			in.read(data);
			return Observable.just(new String(data));
		} catch (Exception e) {
			log.error(e.toString(), e);
		}
		return null;
	}
}
